#!/bin/bash
{
# DietPi-Update incremental patches to apply system and software migrations and fixes
# Created by MichaIng / micha@dietpi.com / https://dietpi.com/
# License: GPLv2 / https://github.com/MichaIng/DietPi#license

# v7.1: Update changed hardware IDs before dietpi-obtain_hw_model would reset them to 22
if [[ -f '/etc/.dietpi_hw_model_identifier' ]]
then
	G_HW_MODEL=$(</etc/.dietpi_hw_model_identifier)
	# https://github.com/MichaIng/DietPi/pull/4193
	if [[ $G_HW_MODEL == 69 ]] # Firefly RK3399
	then
		echo 24 > /etc/.dietpi_hw_model_identifier # Generic Rockchip RK3399

	elif [[ $G_HW_MODEL == 50 || $G_HW_MODEL == 41 || $G_HW_MODEL == 3[54310] ]] # BananaPi M2+, OrangePi PC Plus, OPi Zero 2 Plus, OrangePi Plus, OrangePi Lite, OrangePi One, OrangePi PC
	then
		echo 25 > /etc/.dietpi_hw_model_identifier # Generic Allwinner H3

	elif [[  $G_HW_MODEL == 3[87] ]] # OPi PC2, OPi Prime
	then
		echo 26 > /etc/.dietpi_hw_model_identifier # Generic Allwinner H5
	fi
fi

# Load DietPi-Globals
/boot/dietpi/func/dietpi-obtain_hw_model # Always update
. /boot/dietpi/func/dietpi-globals
readonly G_PROGRAM_NAME='DietPi-Patch'
G_CHECK_ROOT_USER
G_CHECK_ROOTFS_RW
G_INIT

# Prevent backup prompts during patching e.g. from DietPi-Software reinstalls
export G_PROMPT_BACKUP_DISABLED=1
# Prevent initial and final service control during DietPi-Software reinstalls
export G_SERVICE_CONTROL=0

# Version-based incremental patches
Patch_7_0()
{
	# Remove obsolete udev rule, as WiFi power saving is disabled via /etc/network/intefaces > "wireless-power off" > /etc/network/if-pre-up.d/wireless-tools (wireless-tools package) when the WiFi interface is configured.
	[[ -f '/etc/udev/rules.d/10-wifi-disable-powermanagement.rules' ]] && G_EXEC rm /etc/udev/rules.d/10-wifi-disable-powermanagement.rules
}

Patch_7_1()
{
	# Migrate from DietPi-NordVPN to DietPi-VPN
	[[ -f '/boot/dietpi/misc/dietpi-nordvpn' ]] && G_EXEC rm /boot/dietpi/misc/dietpi-nordvpn
	[[ -d '/var/lib/dietpi/dietpi-software/installed/dietpi-nordvpn' ]] && G_EXEC mv /var/lib/dietpi/dietpi-software/installed/dietpi-nordvpn /var/lib/dietpi/dietpi-vpn
	if [[ -f '/var/lib/dietpi/dietpi-vpn/settings_dietpi.conf' ]]
	then
		G_EXEC sed -Ei 's/^NORDVPN_(SERVER|USERNAME|PASSWORD)=/VPN_\1=/' /var/lib/dietpi/dietpi-vpn/settings_dietpi.conf
		. /var/lib/dietpi/dietpi-vpn/settings_dietpi.conf
		[[ -f '/etc/openvpn/client.ovpn' ]] || G_EXEC cp -a "/etc/openvpn/ovpn_$PROTOCOL/$VPN_SERVER" /etc/openvpn/client.ovpn
		unset -v VPN_SERVER PROTOCOL VPN_USERNAME VPN_PASSWORD
		G_EXEC sed -i 's|/var/lib/dietpi/dietpi-software/installed/dietpi-nordvpn/|/var/lib/dietpi/dietpi-vpn/|' /etc/openvpn/client.ovpn
	fi
	if [[ -f '/etc/systemd/system/dietpi-nordvpn.service' ]]
	then
		systemctl -q is-enabled dietpi-nordvpn && G_EXEC systemctl enable dietpi-vpn
		G_EXEC systemctl disable dietpi-nordvpn
		G_EXEC rm /etc/systemd/system/dietpi-nordvpn.service
	fi

	# MariaDB: Rename config file: https://github.com/MichaIng/DietPi/commit/c306d449a7c4ed86a1e9ff7c4914d9e1c2afd11a
	[[ -f '/etc/mysql/mariadb.conf.d/99-dietpi-4byte.cnf' ]] && G_EXEC mv /etc/mysql/mariadb.conf.d/99-dietpi-4byte.cnf /etc/mysql/mariadb.conf.d/97-dietpi.cnf

	# RPi: Additionally blacklist the bcm2835_isp kernel module when the RPi camera feature is disabled: https://github.com/MichaIng/DietPi/issues/4203
	[[ -f '/etc/modprobe.d/dietpi-disable_rpi_camera.conf' ]] && ! grep -q 'bcm2835_isp' /etc/modprobe.d/dietpi-disable_rpi_camera.conf && echo 'blacklist bcm2835_isp' >> /etc/modprobe.d/dietpi-disable_rpi_camera.conf

	# Mark now dedicated Go as installed if OpenBazaar is
	[[ -d '/usr/local/go' ]] && ! grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[188\]=2' /boot/dietpi/.installed && grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[58\]=2' /boot/dietpi/.installed && G_CONFIG_INJECT 'aSOFTWARE_INSTALL_STATE\[188\]=' 'aSOFTWARE_INSTALL_STATE[188]=2' /boot/dietpi/.installed

	# Interactively inform user about possible No-IP => DietPi-DDNS migration
	[[ -f '/boot/dietpi/.installed' ]] && grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[67\]=2' /boot/dietpi/.installed && G_WHIP_MSG '[ INFO ] No-IP client installation found
\nThe No-IP client install option has been replaced by our new DietPi-DDNS tool. The No-IP client remains functional on your system but we recommend a migration to our new tool.
\nSimply run "dietpi-ddns" from console, select "No-IP" as provider, enter domain and credentials, then select "Apply". The old No-IP client and service will be removed automatically as last step, once a final DDNS update test succeeded.'

	# Remove obsolete DietPi-NordVPN and No-IP install states
	[[ -f '/boot/dietpi/.installed' ]] && grep -qE '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[(67|171)\]=' /boot/dietpi/.installed && G_EXEC sed -Ei '/^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[(67|171)\]=/d' /boot/dietpi/.installed

	# Inform user about possible Sonarr v2 => v3 upgrade
	[[ -f '/mnt/dietpi_userdata/sonarr/nzbdrone.pid' ]] && G_WHIP_MSG '[ INFO ] Sonarr v3 has been released
\nYou seem to use Sonarr v2 while Sonarr v3 is now available. A migration is safe to do, but in some cases you might need to redo some configuration, so we do not force the upgrade now.
\nTo migrate to Sonarr v3, run the following command from console:
 - dietpi-software reinstall 144
\nNB: If you use DietPi-Arr_to_RAM and update database backups via Sonarr "Custom Scripts" feature, the following change is required:
 - Run "dietpi-arr_to_ram 2" once manually, which updates your database backup but also creates a new script.
 - Use that script /mnt/dietpi_userdata/sonarr/dietpi-arr_to_ram.sh without arguments to update your database backup via "Custom Scripts". This is required as Sonarr v3 does not allow arguments for custom scripts and does not allow to call scripts from within the /boot directory.'

	# Removing obsolete DietPi-Arr_to_RAM backup files
	rm -f /mnt/dietpi_userdata/{{sonarr,radarr}/nzbdrone.db-{shm,wal},lidarr/lidarr.db-{shm,wal}}.bak

	# On 64-bit RPi systems, remove the obsolete foreign architecture armhf
	[[ $G_HW_MODEL -le 9 && $G_HW_ARCH == 3 && $(dpkg --print-architecture) == 'arm64' ]] && ! dpkg-query -l '*:armhf' &> /dev/null && G_EXEC dpkg --remove-architecture 'armhf'

	# Plex Media Server: Fix secure remote access via app.plex.tv did not work if Unbound with DNS rebinding protection is installed: https://dietpi.com/phpbb/viewtopic.php?t=8896
	[[ -f '/boot/dietpi/.installed' ]] && grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[42\]=2' /boot/dietpi/.installed && grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[182\]=2' /boot/dietpi/.installed && echo -e 'server:\n\tprivate-domain: "plex.direct"' > /etc/unbound/unbound.conf.d/dietpi-plex.conf
}

Patch_7_2()
{
	# Odroid XU4 does not support rng-tools: https://github.com/MichaIng/DietPi/issues/4318
	if [[ $G_HW_MODEL == 11 ]]
	then
		dpkg-query -s rng-tools5 &> /dev/null && G_AGP rng-tools5
		dpkg-query -s rng-tools &> /dev/null && G_AGP rng-tools
		dpkg-query -s rng-tools-debian &> /dev/null && G_AGP rng-tools-debian
		dpkg-query -s haveged &> /dev/null || G_AGI haveged
	fi

	# raspimjpeg: Move executable to a common system path
	if [[ -f '/boot/dietpi/.installed' ]] && grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[59\]=2' /boot/dietpi/.installed
	then
		G_DIETPI-NOTIFY 2 'Moving raspimjpeg executable to a common system path'
		[[ -f '/opt/vc/bin/raspimjpeg' ]] && G_EXEC mv /{opt/vc,usr/local}/bin/raspimjpeg
		[[ -L '/usr/bin/raspimjpeg' ]] && G_EXEC rm /usr/bin/raspimjpeg
	fi

	# Bitwarden_RS: Rename into vaultwarden: https://github.com/MichaIng/DietPi/issues/4325
	if [[ -d '/mnt/dietpi_userdata/bitwarden_rs' ]]
	then
		G_DIETPI-NOTIFY 2 'vaultwarden will be reinstalled now.'
		# Remove Bitwarden_RS service
		if [[ -f '/etc/systemd/system/bitwarden_rs.service' ]]
		then
			G_EXEC systemctl disable --now bitwarden_rs
			G_EXEC rm /etc/systemd/system/bitwarden_rs.service
		fi
		[[ -d '/etc/systemd/system/bitwarden_rs.service.d' ]] && G_EXEC rm -R /etc/systemd/system/bitwarden_rs.service.d
		# Remove Bitwarden_RS user and group
		getent passwd bitwarden_rs > /dev/null && G_EXEC userdel bitwarden_rs
		getent group bitwarden_rs > /dev/null && G_EXEC groupdel bitwarden_rs
		# Remove Bitwarden_RS install directory
		[[ -d '/opt/bitwarden_rs' ]] && G_EXEC rm -R /opt/bitwarden_rs
		# Update and rename Bitwarden_RS config file
		if [[ -f '/mnt/dietpi_userdata/bitwarden_rs/bitwarden_rs.env' ]]
		then
			G_CONFIG_INJECT 'DATA_FOLDER=' 'DATA_FOLDER=/mnt/dietpi_userdata/vaultwarden' /mnt/dietpi_userdata/bitwarden_rs/bitwarden_rs.env
			G_EXEC mv /mnt/dietpi_userdata/bitwarden_rs/{bitwarden_rs,vaultwarden}.env
		fi
		G_EXEC mv /mnt/dietpi_userdata/{bitwarden_rs,vaultwarden}
		# Start vaultwarden reinstallation
		/boot/dietpi/dietpi-software reinstall 183 || G_WHIP_MSG '[WARNING] The vaultwarden (re)install failed.
\nHowever, all required dietpi-update migration steps have been done and it will hence finish.
\nRepeat the reinstall manually to bring up your new vaultwarden instance, when you find time: "dietpi-software reinstall 183"'
	fi

	# Fix disabling dietpi-desktop_setup
	[[ -f '/var/lib/dietpi/dietpi-software/installed/desktop/dietpi-desktop_setup.sh' ]] && grep -q 'echo -e' /var/lib/dietpi/dietpi-software/installed/desktop/dietpi-desktop_setup.sh && G_EXEC sed -i 's/echo -e/echo/' /var/lib/dietpi/dietpi-software/installed/desktop/dietpi-desktop_setup.sh
	for i in /{root,home/*}/.config/autostart/dietpi-desktop_setup.desktop
	do
		[[ -f $i ]] && grep -q '^-e ' "$i" && G_EXEC sed -i 's/^-e //' "$i"
	done

	# LibSSL1.0.0: Remove obsolete install state
	[[ -f '/boot/dietpi/.installed' ]] && grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[126\]=' /boot/dietpi/.installed && G_EXEC sed -i '/^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[126\]=/d' /boot/dietpi/.installed

	# Roon Extension Manager: Inform users about available upgrade: https://github.com/MichaIng/DietPi/pull/4399
	[[ -f '/boot/dietpi/.installed' ]] && grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[86\]=2' /boot/dietpi/.installed && G_WHIP_MSG '[ INFO ] Roon Extension Manager: Major upgrade available
\nThe Roon Extension Manager received a major upgrade to v1.0. It is now implemented as Docker container, rather than as Node.js module.
\nYou may upgrade via: dietpi-software reinstall 86
\nNB: Roon extensions which were installed via the legacy method must be reinstalled with the new Roon Extension Manager. Extensions which were installed as Docker images already, will continue to function.'

	# Pi-hole: Whitelist domain of GEO IP API we use in banner and DietPi-VPN as this is part of public blocklists: https://github.com/MichaIng/DietPi/pull/4398#issuecomment-845477200
	if command -v pihole > /dev/null
	then
		G_DIETPI-NOTIFY 2 'Whitelisting "freegeoip.app" in Pi-hole, which is used by dietpi-banner and dietpi-vpn to obtain your public IP and location...'
		pihole -w freegeoip.app --comment 'Used by dietpi-banner and dietpi-vpn to obtain your public IP and location'
	fi

	# Inform about available software updates
	if [[ -f '/boot/dietpi/.installed' ]]
	then
		# Amiberry
		grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[108\]=2' /boot/dietpi/.installed && G_WHIP_MSG '[ INFO ] Amiberry update available
\nAn update to Amiberry v4.1.2 is available. Apply it via reinstall:
# dietpi-software reinstall 108
\nRelease notes: https://github.com/midwan/amiberry/releases'
		# Shairport Sync
		grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[37\]=2' /boot/dietpi/.installed && G_WHIP_MSG '[ INFO ] Shairport Sync update available
\nAn update to Shairport Sync v3.3.8 is available. Apply it via reinstall:
# dietpi-software reinstall 37
\nRelease notes: https://github.com/mikebrady/shairport-sync/releases'
		# Squeezelite
		grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[36\]=2' /boot/dietpi/.installed && G_WHIP_MSG '[ INFO ] Squeezelite update available
\nAn update to Squeezelite v1.9.9 is available. Apply it via reinstall:
# dietpi-software reinstall 36
\nChange log: https://github.com/ralph-irving/squeezelite/commits/556de56'
	fi
}

# v6.35 => v7 migration
if (( $G_DIETPI_VERSION_CORE == 6 && $G_DIETPI_VERSION_SUB > 34 ))
then
	G_DIETPI_VERSION_CORE=7
	G_DIETPI_VERSION_SUB=-1

# Failsafe: Error out on invalid version
elif ! (( $G_DIETPI_VERSION_CORE > 6 ))
then
	G_DIETPI-NOTIFY 1 "Unsupported DietPi version $G_DIETPI_VERSION_CORE.$G_DIETPI_VERSION_SUB.$G_DIETPI_VERSION_RC. Aborting..."
	G_DIETPI-NOTIFY 2 'Please run "dietpi-update" to repeat the regular update path.'
	exit 1
fi

Patch_7_3()
{
	# If the user did not remove the "dietpi" sodoers manually, update it to allow "sudo -u <user> -g <group>" with all target users and groups.
	# This is required to call our software CLI wrapper scripts, which contain "sudo -u <service_user>" to assure correct config and data is loaded.
	[[ -f '/etc/sudoers.d/dietpi' ]] && echo 'dietpi ALL=(ALL:ALL) NOPASSWD: ALL' > /etc/sudoers.d/dietpi

	# When haveged from Bullseye was installed on Buster (on ARM to workaround a bug), mark the related library as auto-installed so that it can be autoremoved when haveged itself is removed.
	dpkg-query -s haveged &> /dev/null && dpkg-query -s libhavege2 &> /dev/null && G_EXEC apt-mark auto libhavege2

	# Update DietPi-Backup filter file
	if [[ -f '/boot/dietpi/.dietpi-backup_inc_exc' && $(head -1 /boot/dietpi/.dietpi-backup_inc_exc) != '# DietPi-Backup include/exclude filter' ]]
	then
		G_DIETPI-NOTIFY 2 'Updating DietPi-Backup filter file: /boot/dietpi/.dietpi-backup_inc_exc'
		if grep -q '^[[:blank:]]*[^#]' /boot/dietpi/.dietpi-backup_inc_exc
		then
			cat << _EOF_ > .dietpi-backup_inc_exc
# DietPi-Backup include/exclude filter

# Prefix "-" exclude items, "+" include items which would match a wildcard exclude rule.
# Suffix "/" match directories only, no files or symlinks.
# Using wildcard "*" matches any item name or part of it.
# Since the list is processed from top to bottom and the first match defines the result,
#   includes need to be defined before their wildcard exclude rule
#   and in case excludes before their wildcard include rule.
# Symlinks are handled as such and never processed recursively.
# Excluded directories are not processed recursively, so contained items cannot be included.
# Hence, to include items within an excluded directory:
# - Do not exclude the directory itself, but contained items via wildcard.
# - Define includes first, to override the wildcard exclude rule.
# - See the below default rules, how we exclude all items below /mnt
#   but include the dietpi_userdata directory, if it is no symlink.
# To prevent loops, the backup target dir, log and config are excluded internally.

+ /mnt/dietpi_userdata/
- /mnt/*
- /media/

$(grep '^[[:blank:]]*[^#]' /boot/dietpi/.dietpi-backup_inc_exc)
_EOF_
			G_EXEC mv {,/boot/dietpi/}.dietpi-backup_inc_exc
		else
			G_EXEC rm /boot/dietpi/.dietpi-backup_inc_exc
		fi
	fi

	# RPi: Remove deprecated I2C setting from config.txt
	(( $G_HW_MODEL > 9 )) || G_EXEC sed -i '/dtparam=i2c1=/d' /boot/config.txt

	# Tomcat 8: Remove obsolete install state
	[[ -f '/boot/dietpi/.installed' ]] && grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[125\]=' /boot/dietpi/.installed && G_EXEC sed -i '/^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[125\]=/d' /boot/dietpi/.installed

	# Remove license (flag) file if AUTO_SETUP_AUTOMATED=1 is set, which would otherwise never happen on pre-v7.2 images, and if AUTO_SETUP_ACCEPT_LICENSE=1 is set, to assure the prompt is skipped when for some reason the script is reloaded between update and first installs.
	[[ -f '/var/lib/dietpi/license.txt' ]] && grep -Eq '^[[:blank:]]*AUTO_SETUP_A(UTOMATED|CCEPT_LICENSE)=1' /boot/dietpi.txt && G_EXEC rm /var/lib/dietpi/license.txt

	# Update Allo web UI with Squeezelite control fix and Allo Boss2 DAC support
	[[ -f '/boot/dietpi/.installed' ]] && grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[160\]=2' /boot/dietpi/.installed && /boot/dietpi/dietpi-software reinstall 160
}

Patch_7_4()
{
	if [[ $G_HW_ARCH == [12] && ! -f '/etc/pip.conf' && -f '/boot/dietpi/.installed' ]] && grep -q '^[[:blank:]]*aSOFTWARE_INSTALL_STATE\[130\]=2' /boot/dietpi/.installed
	then
		G_WHIP_BUTTON_CANCEL_TEXT='No' G_WHIP_YESNO 'Adding piwheels.org to your pip sources
\nPython 3 pip is installed on your system, but piwheels.org is not used as source for pre-compiled Python 3 wheels. To speed up the installation and upgrade of modules via pip and reduce build dependencies, we highly recommend to make use of it.
\nRead more about the project at: https://piwheels.org/
\nDo you want pip to pull Python 3 wheels from piwheels.org automatically?' && G_EXEC eval "echo -e '[global]\nextra-index-url=https://www.piwheels.org/simple/' > /etc/pip.conf"
	fi
}

# Main loop
while :
do
	((G_DIETPI_VERSION_SUB++))
	G_DIETPI_VERSION_RC=0
	declare -F "Patch_${G_DIETPI_VERSION_CORE}_$G_DIETPI_VERSION_SUB" > /dev/null || break
	G_DIETPI-NOTIFY 2 "Patching to DietPi v$G_DIETPI_VERSION_CORE.$G_DIETPI_VERSION_SUB..."
	"Patch_${G_DIETPI_VERSION_CORE}_$G_DIETPI_VERSION_SUB"
	G_VERSIONDB_SAVE
	G_DIETPI-NOTIFY 0 "Patched to DietPi v$G_DIETPI_VERSION_CORE.$G_DIETPI_VERSION_SUB"
done

exit 0
}
